#ifndef CHIPLAB_EMU_H
#define CHIPLAB_EMU_H

#include <verilated.h>
#include <verilated_save.h>
#include "cpu_tool.h"
#include "diff_manage.h"
#include "common.h"
#include "lightsss.h"


#define CONFREG_UART_DATA       top->confreg_uart_data
#define CONFREG_UART_DISPLAY    top->write_uart_valid

class Emulator:CpuTool {
private:
    vluint64_t *main_time;
    int trapCode;
    bool need_wakeup=false;
    /* init ram. The ram img will be mapped to NEMU. */
    void init_ram(const char*path, const char *file_in);
    uint64_t lasttime_snapshot = 0;
    LightSSS *lightsss = NULL;
    void fork_child_init();
    inline bool is_fork_child() {
        return lightsss->is_child();
    }
public:
    DiffManage* dm;

    /* input: ram img path */
    char img[128];
    /* output path */
    char simu_out_path[128];
    char uart_out_path[128];

    Emulator(Vtop *top, const char*path, const char* file_out, const char*uart_path, const char*file_in, const char*data_vlog);
    ~Emulator();

    /* do init work such as init_difftest, init_nemuproxy */
    void init_emu(vluint64_t* main_time);
    void init_random_vlog(const char *path, const char *file_in);
    void set_need_wakeup(){
        need_wakeup=true;
    }

    uint32_t uptime(){
        struct timeval t;
        gettimeofday(&t, NULL);
        int s = t.tv_sec - start.tv_sec;
        int us = t.tv_usec - start.tv_usec;
        if (us < 0) {
            s--;
            us += 1000000;
        }
        return s * 1000 + (us + 500) / 1000;
    }//Obtain the time in milliseconds.
    /* difftest execute one step to compare dut and ref */
    int process();
    /* used by slice */
    void close();
};

#endif //CHIPLAB_EMU_H
